package edu.northwestern.cbits.purple_robot_manager.scripting; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Matrix; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.provider.Browser; import android.provider.MediaStore; import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.widget.RemoteViews; import android.widget.Toast; import edu.northwestern.cbits.purple_robot_manager.EncryptionManager; import edu.northwestern.cbits.purple_robot_manager.ManagerService; import edu.northwestern.cbits.purple_robot_manager.PurpleRobotApplication; import edu.northwestern.cbits.purple_robot_manager.R; import edu.northwestern.cbits.purple_robot_manager.ScheduleManager; import edu.northwestern.cbits.purple_robot_manager.activities.DialogActivity; import edu.northwestern.cbits.purple_robot_manager.activities.LabelActivity; import edu.northwestern.cbits.purple_robot_manager.activities.NfcActivity; import edu.northwestern.cbits.purple_robot_manager.activities.TestActivity; import edu.northwestern.cbits.purple_robot_manager.activities.WebActivity; import edu.northwestern.cbits.purple_robot_manager.activities.settings.SettingsKeys; import edu.northwestern.cbits.purple_robot_manager.annotation.ScriptingEngineMethod; import edu.northwestern.cbits.purple_robot_manager.config.LegacyJSONConfigFile; import edu.northwestern.cbits.purple_robot_manager.logging.LogManager; import edu.northwestern.cbits.purple_robot_manager.models.ModelManager; import edu.northwestern.cbits.purple_robot_manager.plugins.DataUploadPlugin; import edu.northwestern.cbits.purple_robot_manager.plugins.OutputPlugin; import edu.northwestern.cbits.purple_robot_manager.plugins.OutputPluginManager; import edu.northwestern.cbits.purple_robot_manager.probes.ProbeManager; import edu.northwestern.cbits.purple_robot_manager.snapshots.EmptySnapshotException; import edu.northwestern.cbits.purple_robot_manager.snapshots.SnapshotManager; import edu.northwestern.cbits.purple_robot_manager.triggers.Trigger; import edu.northwestern.cbits.purple_robot_manager.triggers.TriggerManager; import edu.northwestern.cbits.purple_robot_manager.util.ImageUtils; import edu.northwestern.cbits.purple_robot_manager.widget.PurpleRobotAppWideWidgetProvider; import edu.northwestern.cbits.purple_robot_manager.widget.PurpleRobotAppWidgetProvider; public abstract class BaseScriptEngine { public static String SCRIPT_ENGINE_PERSISTENCE_PREFIX = "purple_robot_script_persist_prefix_"; protected static String SCRIPT_ENGINE_NAMESPACES = "purple_robot_script_namespaces"; public static final int NOTIFICATION_ID = (int) System.currentTimeMillis(); public static final String STICKY_NOTIFICATION_PARAMS = "STICKY_NOTIFICATION_PARAMS"; private static String LOG_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS"; protected Context _context = null; private static Map<String, String> packageMap = null; private final Handler _handler = new Handler(Looper.getMainLooper()); protected abstract String language(); public BaseScriptEngine(Context context) { this._context = context; } public Date dateFromTimestamp(long epoch) { return new Date(epoch); } public String formatDate(Date date) { return ScheduleManager.formatString(date); } public Date parseDate(String dateString) { return ScheduleManager.parseString(dateString); } public Date now() { return ScheduleManager.clearMillis(new Date()); } @SuppressLint("SimpleDateFormat") @ScriptingEngineMethod(language = "All", assetPath = "all_log.html", category = R.string.docs_script_category_diagnostic, arguments = { "message" }) public void log(Object message) { SimpleDateFormat sdf = new SimpleDateFormat(BaseScriptEngine.LOG_DATE_FORMAT); Log.e("PR." + this.language(), sdf.format(new Date()) + ": " + message.toString()); HashMap<String, Object> payload = new HashMap<>(); payload.put("message", message); LogManager.getInstance(this._context).log("pr_script_log_message", payload); } public void testLog(Object message) { this.log(message); LocalBroadcastManager bcast = LocalBroadcastManager.getInstance(this._context); Intent intent = new Intent(TestActivity.INTENT_PROGRESS_MESSAGE); intent.putExtra(TestActivity.PROGRESS_MESSAGE, message.toString()); bcast.sendBroadcastSync(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_stop_playback.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { }) public void stopPlayback() { Intent intent = new Intent(ManagerService.RINGTONE_STOP_INTENT); intent.setClass(this._context, ManagerService.class); HashMap<String, Object> payload = new HashMap<>(); LogManager.getInstance(this._context).log("pr_tone_stopped", payload); this._context.startService(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_play_default_tone.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "loops" }) public void playDefaultTone(boolean loops) { LogManager.getInstance(this._context).log("pr_default_tone_played", null); this.playTone(null, loops); } @ScriptingEngineMethod(language = "All", assetPath = "all_play_default_tone.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "loops" }) public void playDefaultTone() { this.playDefaultTone(false); } @ScriptingEngineMethod(language = "All", assetPath = "all_play_tone.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "tone", "loops" }) public void playTone(String tone) { this.playTone(tone, false); } @ScriptingEngineMethod(language = "All", assetPath = "all_play_tone.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "tone", "loops" }) public void playTone(String tone, boolean loops) { Intent intent = new Intent(ManagerService.RINGTONE_INTENT); intent.setClass(this._context, ManagerService.class); Log.e("PR", "TONE: " + tone); if (tone != null) intent.putExtra(ManagerService.RINGTONE_NAME, tone); if (loops) intent.putExtra(ManagerService.RINGTONE_LOOPS, loops); HashMap<String, Object> payload = new HashMap<>(); payload.put("tone", tone); LogManager.getInstance(this._context).log("pr_tone_played", payload); this._context.startService(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_persist_encrypted_string.html", category = R.string.docs_script_category_persistence, arguments = { "key", "value" }) public boolean persistEncryptedString(String key, String value) { key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; return EncryptionManager.getInstance().persistEncryptedString(this._context, key, value); } @ScriptingEngineMethod(language = "All", assetPath = "all_persist_encrypted_string.html", category = R.string.docs_script_category_persistence, arguments = { "key", "value" }) public boolean persistEncryptedString(String namespace, String key, String value) { key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; key = namespace + " - " + key; return EncryptionManager.getInstance().persistEncryptedString(this._context, key, value); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_encrypted_string.html", category = R.string.docs_script_category_persistence, arguments = { "key" }) public String fetchEncryptedString(String key) { key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; return EncryptionManager.getInstance().fetchEncryptedString(this._context, key); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_encrypted_string.html", category = R.string.docs_script_category_persistence, arguments = { "key" }) public String fetchEncryptedString(String namespace, String key) { key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; key = namespace + " - " + key; return EncryptionManager.getInstance().fetchEncryptedString(this._context, key); } @ScriptingEngineMethod(language = "All", assetPath = "all_vibrate.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "pattern", "repeats" }) public void vibrate(String pattern) { this.vibrate(pattern, false); } @ScriptingEngineMethod(language = "All", assetPath = "all_vibrate.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "pattern", "repeats" }) public void vibrate(String pattern, boolean repeats) { Intent intent = new Intent(ManagerService.HAPTIC_PATTERN_INTENT); intent.putExtra(ManagerService.HAPTIC_PATTERN_NAME, pattern); intent.putExtra(ManagerService.HAPTIC_PATTERN_REPEATS, repeats); intent.setClass(this._context, ManagerService.class); HashMap<String, Object> payload = new HashMap<>(); payload.put("pattern", pattern); LogManager.getInstance(this._context).log("pr_vibrate_device", payload); this._context.startService(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_stop_vibrate.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { }) public void stopVibrate() { ManagerService.stopAllVibrations(); } @ScriptingEngineMethod(language = "All", assetPath = "all_read_url.html", category = R.string.docs_script_category_data_collection, arguments = { "url", "lenient" }) public String readUrl(String urlString) { return this.readUrl(urlString, false); } @ScriptingEngineMethod(language = "All", assetPath = "all_read_url.html", category = R.string.docs_script_category_data_collection, arguments = { "url", "lenient" }) public String readUrl(String urlString, boolean lenient) { try { if (lenient) { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // Create all-trusting host name verifier HostnameVerifier allHostsValid = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { // TODO Auto-generated method stub return true; } }; // Install the all-trusting host verifier HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); } URL url = new URL(urlString); URLConnection connection = url.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuilder response = new StringBuilder(); String inputLine; while ((inputLine = in.readLine()) != null) response.append(inputLine); in.close(); return response.toString(); } catch (Exception e) { LogManager.getInstance(this._context).logException(e); } return null; } @ScriptingEngineMethod(language = "All", assetPath = "all_emit_toast.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "message", "useLongDuration" }) public boolean emitToast(final String message) { return this.emitToast(message, false); } @ScriptingEngineMethod(language = "All", assetPath = "all_emit_toast.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "message", "useLongDuration" }) public boolean emitToast(final String message, final boolean useLongDuration) { HashMap<String, Object> payload = new HashMap<>(); payload.put("has_activity", (this._context instanceof Activity)); payload.put("message", message); LogManager.getInstance(this._context).log("pr_toast_message", payload); final BaseScriptEngine me = this; this._handler.post(new Runnable() { @Override public void run() { if (useLongDuration) Toast.makeText(me._context, message, Toast.LENGTH_LONG).show(); else Toast.makeText(me._context, message, Toast.LENGTH_SHORT).show(); } }); return true; } @ScriptingEngineMethod(language = "All", assetPath = "all_launch_url.html", category = R.string.docs_script_category_system_integration, arguments = { "url" }) public boolean launchUrl(String urlString) { try { Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlString)); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); launchIntent.putExtra(Browser.EXTRA_APPLICATION_ID, this._context.getPackageName()); this._context.startActivity(launchIntent); HashMap<String, Object> payload = new HashMap<>(); payload.put("url", urlString); LogManager.getInstance(this._context).log("pr_launch_url", payload); return true; } catch (Exception e) { LogManager.getInstance(this._context).logException(e); } return false; } @ScriptingEngineMethod(language = "All", assetPath = "all_launch_internal_url.html", category = R.string.docs_script_category_system_integration, arguments = { "url" }) public boolean launchInternalUrl(String urlString) { if (urlString.startsWith("file:///android_asset/") || urlString.startsWith("https://") || urlString.startsWith("http://")) { Intent launchIntent = new Intent(this._context, WebActivity.class); launchIntent.setData(Uri.parse(urlString)); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); this._context.startActivity(launchIntent); HashMap<String, Object> payload = new HashMap<>(); payload.put("url", urlString); LogManager.getInstance(this._context).log("pr_launch_internal_url", payload); return true; } return false; } @SuppressLint("DefaultLocale") @ScriptingEngineMethod(language = "All", assetPath = "all_package_for_application_name.html", category = R.string.docs_script_category_system_integration, arguments = { "applicationName" }) public String packageForApplicationName(String applicationName) { if (applicationName == null) return null; if (BaseScriptEngine.packageMap == null) { BaseScriptEngine.packageMap = new HashMap<>(); String[] keyArray = this._context.getResources().getStringArray(R.array.app_package_keys); String[] valueArray = this._context.getResources().getStringArray(R.array.app_package_values); if (keyArray.length == valueArray.length) { for (int i = 0; i < keyArray.length; i++) { BaseScriptEngine.packageMap.put(keyArray[i].toLowerCase(), valueArray[i]); } } } String packageName = BaseScriptEngine.packageMap.get(applicationName.toLowerCase()); if (packageName == null) packageName = applicationName; // Allows us to launch by package // name as well. PackageManager pkgManager = this._context.getPackageManager(); Intent launchIntent = pkgManager.getLaunchIntentForPackage(packageName); if (launchIntent == null) // No matching package found on system... packageName = null; if (packageName == null) { List<ApplicationInfo> apps = this._context.getPackageManager().getInstalledApplications(PackageManager.GET_META_DATA); for (ApplicationInfo app : apps) { String thisAppName = app.loadLabel(this._context.getPackageManager()).toString(); if (applicationName.toLowerCase().equals(thisAppName.toLowerCase())) return app.packageName; } } try { if (this._context.getPackageManager().getPackageInfo(applicationName, 0) != null) return applicationName; } catch (NameNotFoundException e) { e.printStackTrace(); } return null; } @ScriptingEngineMethod(language = "All", assetPath = "all_version.html", category = R.string.docs_script_category_diagnostic, arguments = { }) public String version() { try { PackageInfo info = this._context.getPackageManager().getPackageInfo(this._context.getPackageName(), 0); return info.versionName; } catch (NameNotFoundException e) { LogManager.getInstance(this._context).logException(e); } return null; } @ScriptingEngineMethod(language = "All", assetPath = "all_version_code.html", category = R.string.docs_script_category_diagnostic, arguments = { }) public int versionCode() { try { PackageInfo info = this._context.getPackageManager().getPackageInfo(this._context.getPackageName(), 0); return info.versionCode; } catch (NameNotFoundException e) { LogManager.getInstance(this._context).logException(e); } return -1; } @ScriptingEngineMethod(language = "All", assetPath = "all_persist_string.html", category = R.string.docs_script_category_persistence, arguments = { "key", "value" }) public boolean persistString(String key, String value) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor editor = prefs.edit(); key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; if (value != null) editor.putString(key, value.toString()); else editor.remove(key); return editor.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_add_namespace.html", category = R.string.docs_script_category_persistence, arguments = { "namespace" }) public void addNamespace(String namespace) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); try { JSONArray namespaces = new JSONArray(prefs.getString(BaseScriptEngine.SCRIPT_ENGINE_NAMESPACES, "[]")); for (int i = 0; i < namespaces.length(); i++) { String item = namespaces.getString(i); if (item.equals(namespace)) return; } namespaces.put(namespace); Editor e = prefs.edit(); e.putString(BaseScriptEngine.SCRIPT_ENGINE_NAMESPACES, namespaces.toString()); e.commit(); } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } } public List<String> namespaceList() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); ArrayList<String> namespaceList = new ArrayList<>(); try { JSONArray namespaces = new JSONArray(prefs.getString(BaseScriptEngine.SCRIPT_ENGINE_NAMESPACES, "[]")); for (int i = 0; i < namespaces.length(); i++) { namespaceList.add(namespaces.getString(i)); } } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } return namespaceList; } @ScriptingEngineMethod(language = "All", assetPath = "all_persist_string.html", category = R.string.docs_script_category_persistence, arguments = { "key", "value" }) public boolean persistString(String namespace, String key, String value) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor editor = prefs.edit(); this.addNamespace(namespace); key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; key = namespace + " - " + key; if (value != null) editor.putString(key, value.toString()); else editor.remove(key); return editor.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_string.html", category = R.string.docs_script_category_persistence, arguments = { "key" }) public String fetchString(String namespace, String key) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; key = namespace + " - " + key; return prefs.getString(key, null); } // Not documented in favor of fetchLabels... public void fetchLabel(String context, String key) { Intent labelIntent = new Intent(this._context, LabelActivity.class); labelIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); if (context == null || context.trim().length() < 1) context = this._context.getString(R.string.label_unknown_context); labelIntent.putExtra(LabelActivity.LABEL_CONTEXT, context); if (key != null && key.trim().length() > 1) labelIntent.putExtra(LabelActivity.LABEL_KEY, key); this._context.getApplicationContext().startActivity(labelIntent); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_string.html", category = R.string.docs_script_category_persistence, arguments = { "key" }) public String fetchString(String key) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); key = SCRIPT_ENGINE_PERSISTENCE_PREFIX + key; return prefs.getString(key, null); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_setting.html", category = R.string.docs_script_category_configuration, arguments = { "key" }) public String fetchSetting(String key) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Object value = prefs.getAll().get(key); if (value != null) return value.toString(); return null; } @ScriptingEngineMethod(language = "All", assetPath = "all_reset_trigger.html", category = R.string.docs_script_category_triggers_automation, arguments = { "triggerId" }) public void resetTrigger(String triggerId) { for (Trigger trigger : TriggerManager.getInstance(this._context).triggersForId(triggerId)) { trigger.reset(this._context); } } @ScriptingEngineMethod(language = "All", assetPath = "all_enable_trigger.html", category = R.string.docs_script_category_triggers_automation, arguments = { "triggerId" }) public void enableTrigger(String triggerId) { for (Trigger trigger : TriggerManager.getInstance(this._context).triggersForId(triggerId)) { trigger.setEnabled(this._context, true); } } @ScriptingEngineMethod(language = "All", assetPath = "all_fire_trigger.html", category = R.string.docs_script_category_triggers_automation, arguments = { "triggerId" }) public void fireTrigger(String triggerId) { for (Trigger trigger : TriggerManager.getInstance(this._context).triggersForId(triggerId)) { trigger.execute(this._context, true); } } @ScriptingEngineMethod(language = "All", assetPath = "all_disable_trigger.html", category = R.string.docs_script_category_triggers_automation, arguments = { "triggerId" }) public void disableTrigger(String triggerId) { for (Trigger trigger : TriggerManager.getInstance(this._context).triggersForId(triggerId)) { trigger.setEnabled(this._context, false); } } public void disableAutoConfigUpdates(String triggerId) { // TODO } public void enableAutoConfigUpdates(String triggerId) { // TODO } @ScriptingEngineMethod(language = "All", assetPath = "all_enable_probes.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void enableProbes() { ProbeManager.enableProbes(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_disable_probes.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void disableProbes() { ProbeManager.disableProbes(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_disable_each_probe.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void disableEachProbe() { ProbeManager.disableEachProbe(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_probes_enabled.html", category = R.string.docs_script_category_data_collection, arguments = { }) public boolean probesEnabled() { return ProbeManager.probesState(this._context); } public boolean probesState() { // Left for script compatibility return this.probesEnabled(); } protected void transmitData(Bundle data) { UUID uuid = UUID.randomUUID(); data.putString("GUID", uuid.toString()); LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(this._context); Intent intent = new Intent(edu.northwestern.cbits.purple_robot_manager.probes.Probe.PROBE_READING); intent.putExtras(data); localManager.sendBroadcast(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_disable_probe.html", category = R.string.docs_script_category_data_collection, arguments = {"probeName" }) public void disableProbe(String probeName) { ProbeManager.disableProbe(this._context, probeName); } @ScriptingEngineMethod(language = "All", assetPath = "all_update_config_url.html", category = R.string.docs_script_category_configuration, arguments = { "newConfigUrl" }) public void updateConfigUrl(String newConfigUrl) { if (newConfigUrl != null && newConfigUrl.trim().length() == 0) newConfigUrl = null; EncryptionManager.getInstance().setConfigurationReady(false); EncryptionManager.getInstance().setConfigUri(this._context, Uri.parse(newConfigUrl)); LegacyJSONConfigFile.update(this._context, true); } @ScriptingEngineMethod(language = "All", assetPath = "all_set_password.html", category = R.string.docs_script_category_configuration, arguments = { "password" }) public void setPassword(String password) { if (password == null || password.trim().length() == 0) this.clearPassword(); else { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putString("config_password", password); e.commit(); } } @ScriptingEngineMethod(language = "All", assetPath = "all_clear_password.html", category = R.string.docs_script_category_configuration, arguments = { }) public void clearPassword() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.remove("config_password"); e.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_enable_background_image.html", category = R.string.docs_script_category_configuration, arguments = { }) public void enableBackgroundImage() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putBoolean("config_show_background", true); e.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_is_configuration_ready.html", category = R.string.docs_script_category_diagnostic, arguments = { }) public boolean isConfigurationReady() { return EncryptionManager.getInstance().getConfigurationReady(); } @ScriptingEngineMethod(language = "All", assetPath = "all_uploaders_enabled.html", category = R.string.docs_script_category_diagnostic, arguments = { }) public boolean uploadersEnabled() { OutputPluginManager plugins = OutputPluginManager.getSharedInstance(); for (OutputPlugin plugin : plugins.getPlugins()) { if (plugin instanceof DataUploadPlugin) { DataUploadPlugin uploadPlugin = (DataUploadPlugin) plugin; if (uploadPlugin.isEnabled(this._context)) return true; } } return false; } @ScriptingEngineMethod(language = "All", assetPath = "all_disable_background_image.html", category = R.string.docs_script_category_configuration, arguments = { }) public void disableBackgroundImage() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putBoolean("config_show_background", false); e.commit(); } @ScriptingEngineMethod(language = "All") private void refreshConfigUrl() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor editor = prefs.edit(); editor.putLong(LegacyJSONConfigFile.JSON_LAST_UPDATE, 0); editor.commit(); LegacyJSONConfigFile.update(this._context, true); ProbeManager.nudgeProbes(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_set_user_id.html", category = R.string.docs_script_category_configuration, arguments = { "userId", "refresh" }) public void setUserId(String userId) { this.setUserId(userId, true); } @ScriptingEngineMethod(language = "All", assetPath = "all_set_user_id.html", category = R.string.docs_script_category_configuration, arguments = { "userId", "refresh" }) public void setUserId(String userId, boolean refreshConfig) { HashMap<String, Object> payload = new HashMap<>(); payload.put("source", "BaseScriptEngine"); payload.put("old_id", EncryptionManager.getInstance().getUserId(this._context)); payload.put("new_id", userId); payload.put("refresh_config", refreshConfig); LogManager.getInstance(this._context).log("set_user_id", payload); EncryptionManager.getInstance().setUserId(this._context, userId); try { Thread.sleep(1000); } catch (InterruptedException e) { } if (refreshConfig) this.refreshConfigUrl(); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_user_id.html", category = R.string.docs_script_category_configuration, arguments = { }) public String fetchUserId() { HashMap<String, Object> payload = new HashMap<>(); payload.put("source", "BaseScriptEngine"); LogManager.getInstance(this._context).log("fetch_user_id", payload); return EncryptionManager.getInstance().getUserId(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_fetch_user_hash.html", category = R.string.docs_script_category_configuration, arguments = { }) public String fetchUserHash() { HashMap<String, Object> payload = new HashMap<>(); payload.put("source", "BaseScriptEngine"); LogManager.getInstance(this._context).log("fetch_user_hash", payload); return EncryptionManager.getInstance().getUserHash(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_restore_default_id.html", category = R.string.docs_script_category_configuration, arguments = { }) public void restoreDefaultId() { HashMap<String, Object> payload = new HashMap<>(); payload.put("source", "BaseScriptEngine"); LogManager.getInstance(this._context).log("restore_default_id", payload); EncryptionManager.getInstance().restoreDefaultId(this._context); this.refreshConfigUrl(); } // Left for legacy compatibility purposes... public void enableUpdateChecks() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putBoolean(SettingsKeys.CHECK_UPDATES_KEY, true); e.commit(); } // Left for legacy compatibility purposes... public void disableUpdateChecks() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putBoolean(SettingsKeys.CHECK_UPDATES_KEY, false); e.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_enable_probe.html", category = R.string.docs_script_category_data_collection, arguments = {"probeName" }) public void enableProbe(String probeName) { ProbeManager.enableProbe(this._context, probeName); } protected boolean updateWidget(final String title, final String message, final String applicationName, final Map<String, Object> launchParams, final String script) { AppWidgetManager widgetManager = AppWidgetManager.getInstance(this._context); ComponentName provider = new ComponentName(this._context.getPackageName(), PurpleRobotAppWidgetProvider.class.getName()); int[] widgetIds = widgetManager.getAppWidgetIds(provider); ComponentName wideProvider = new ComponentName(this._context.getPackageName(), PurpleRobotAppWideWidgetProvider.class.getName()); int[] wideWidgetIds = widgetManager.getAppWidgetIds(wideProvider); RemoteViews views = new RemoteViews(this._context.getPackageName(), R.layout.layout_widget); views.setCharSequence(R.id.widget_title_text, "setText", title); views.setCharSequence(R.id.widget_message_text, "setText", message); RemoteViews wideViews = new RemoteViews(this._context.getPackageName(), R.layout.layout_wide_widget); wideViews.setCharSequence(R.id.widget_wide_title_text, "setText", title); wideViews.setCharSequence(R.id.widget_wide_message_text, "setText", message); Intent intent = this.constructLaunchIntent(applicationName, launchParams, script); if (intent != null) { if (intent.getAction().equals(ManagerService.APPLICATION_LAUNCH_INTENT)) { PendingIntent pi = PendingIntent.getService(this._context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.widget_root_layout, pi); wideViews.setOnClickPendingIntent(R.id.widget_root_layout, pi); } else { PendingIntent pi = PendingIntent.getActivity(this._context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.widget_root_layout, pi); wideViews.setOnClickPendingIntent(R.id.widget_root_layout, pi); } } widgetManager.updateAppWidget(widgetIds, views); widgetManager.updateAppWidget(wideWidgetIds, wideViews); return true; } @SuppressLint("DefaultLocale") protected Intent constructLaunchIntent(String applicationName, Map<String, Object> launchParams, String script) { if (applicationName == null) return null; String packageName = this.packageForApplicationName(applicationName); if (packageName != null) { Intent intent = new Intent(ManagerService.APPLICATION_LAUNCH_INTENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_PACKAGE, packageName); if (script != null) intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_POSTSCRIPT, script); if (launchParams != null) { HashMap<String, String> launchMap = new HashMap<>(); for (Entry<String, Object> e : launchParams.entrySet()) { launchMap.put(e.getKey(), e.getValue().toString()); } JSONObject jsonMap = new JSONObject(launchMap); intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_PARAMETERS, jsonMap.toString()); } return intent; } if (applicationName.toLowerCase().startsWith("http://") || applicationName.toLowerCase().startsWith("https://")) { Intent intent = new Intent(ManagerService.APPLICATION_LAUNCH_INTENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_URL, applicationName); if (script != null) intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_POSTSCRIPT, script); if (launchParams != null) { HashMap<String, String> launchMap = new HashMap<>(); for (Entry<String, Object> e : launchParams.entrySet()) { launchMap.put(e.getKey().toString(), e.getValue().toString()); } JSONObject jsonMap = new JSONObject(launchMap); intent.putExtra(ManagerService.APPLICATION_LAUNCH_INTENT_PARAMETERS, jsonMap.toString()); } return intent; } return null; } @SuppressLint("DefaultLocale") protected Intent constructDirectLaunchIntent(final String applicationName, Map<String, Object> launchParams) { if (applicationName.toLowerCase().startsWith("http://") || applicationName.toLowerCase().startsWith("https://")) return new Intent(Intent.ACTION_VIEW, Uri.parse(applicationName)); else { String packageName = this.packageForApplicationName(applicationName); if (packageName != null) { Intent intent = this._context.getPackageManager().getLaunchIntentForPackage(packageName); if (launchParams != null) { for (Entry<String, Object> e : launchParams.entrySet()) { intent.putExtra(e.getKey().toString(), e.getValue().toString()); } } return intent; } } return null; } protected boolean updateTrigger(String triggerId, Map<String, Object> params) { boolean found = false; params.put("identifier", triggerId); for (Trigger trigger : TriggerManager.getInstance(this._context).triggersForId(triggerId)) { trigger.updateFromMap(this._context, params); found = true; } if (!found) { Trigger t = Trigger.parse(this._context, params); TriggerManager.getInstance(this._context).addTrigger(this._context, t); found = true; } return found; } protected boolean updateProbeConfig(Map<String, Object> params) { if (params.containsKey("name")) { String probeName = params.get("name").toString(); return ProbeManager.updateProbe(this._context, probeName, params); } return false; } protected Map<String, Object> probeConfigMap(String name) { return ProbeManager.probeConfiguration(this._context, name); } @ScriptingEngineMethod(language = "All", assetPath = "all_launch_application.html", category = R.string.docs_script_category_system_integration, arguments = { "applicationName", "options", "script" }) public boolean launchApplication(String applicationName) { return this.launchApplication(applicationName, new HashMap<String, Object>(), null); } protected boolean launchApplication(String applicationName, Map<String, Object> launchParams, final String script) { Intent intent = this.constructLaunchIntent(applicationName, launchParams, script); HashMap<String, Object> payload = new HashMap<>(); payload.put("application_present", (intent != null)); payload.put("application_name", applicationName); LogManager.getInstance(this._context).log("pr_application_launch", payload); if (intent != null) { intent.setClass(this._context, ManagerService.class); this._context.startService(intent); return true; } return false; } protected boolean showApplicationLaunchNotification(String title, String message, String applicationName, Map<String, Object> launchParams, final String script) { return this.showApplicationLaunchNotification(title, message, applicationName, false, launchParams, script); } protected boolean showApplicationLaunchNotification(String title, String message, String applicationName, boolean persistent, Map<String, Object> launchParams, final String script) { try { long now = System.currentTimeMillis(); Intent intent = this.constructDirectLaunchIntent(applicationName, launchParams); HashMap<String, Object> payload = new HashMap<>(); payload.put("application_present", (intent != null)); payload.put("application_name", applicationName); LogManager.getInstance(this._context).log("pr_application_launch_notification", payload); if (intent != null) { PendingIntent pendingIntent = PendingIntent.getActivity(this._context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (script != null) { Intent serviceIntent = this.constructLaunchIntent(applicationName, launchParams, script); pendingIntent = PendingIntent.getService(this._context, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT); } NotificationCompat.Builder builder = new NotificationCompat.Builder(this._context); builder.setContentIntent(pendingIntent); builder.setAutoCancel(true); builder.setContentTitle(title); builder.setContentText(message); builder.setTicker(message); builder.setSmallIcon(R.drawable.ic_note_icon); try { Notification note = builder.build(); if (persistent) note.flags = note.flags | Notification.FLAG_NO_CLEAR; NotificationManager noteManager = (NotificationManager) this._context.getSystemService(android.content.Context.NOTIFICATION_SERVICE); noteManager.notify(BaseScriptEngine.NOTIFICATION_ID, note); } catch (UnsupportedOperationException e) { // Added so that the mock test cases could still execute. } return true; } return false; } catch (Exception e) { LogManager.getInstance(this._context).logException(e); } return false; } @ScriptingEngineMethod(language = "All", assetPath = "all_show_script_note.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "title", "message", "persistent", "script", "sticky", "imageUrl" }) public boolean showScriptNotification(String title, String message, boolean persistent, Object... args) { boolean sticky = false; String script = null; String iconUrl = null; for (Object item : args) { if (item instanceof Boolean) sticky = (Boolean) item; else if (item instanceof String) { String value = (String) item; String lowerValue = value.toLowerCase(); if (lowerValue.startsWith("https://") || lowerValue.startsWith("http://") || lowerValue.startsWith("file://")) { iconUrl = value; } else { // Two scripts provided - bail... if (script != null) { HashMap<String, Object> payload = new HashMap<>(); payload.put("message", "Tried to define two script parameters in showScriptNotification."); LogManager.getInstance(this._context).log("script_error", payload); return false; } script = value; } } } return this.showScriptNotification(title, message, persistent, sticky, script, iconUrl); } @ScriptingEngineMethod(language = "All", assetPath = "all_show_script_note.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "title", "message", "persistent", "script", "sticky", "imageUrl" }) public boolean showScriptNotification(final String title, final String message, final boolean persistent, final boolean sticky, final String script, final String iconUrl) { try { HashMap<String, Object> payload = new HashMap<>(); LogManager.getInstance(this._context).log("pr_script_run_notification", payload); Intent serviceIntent = this.constructScriptIntent(script); PendingIntent pendingIntent = PendingIntent.getService(this._context, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this._context); builder = builder.setContentIntent(pendingIntent); if (!sticky) builder = builder.setAutoCancel(true); builder = builder.setContentTitle(title); builder = builder.setContentText(message); builder = builder.setTicker(message); builder = builder.setSmallIcon(R.drawable.ic_note_icon); if (iconUrl != null) { final int side = (int) (40 * this._context.getResources().getDisplayMetrics().density); Uri resized = ImageUtils.fetchResizedImageSync(this._context, Uri.parse(iconUrl), side, side, true); if (resized == null) return false; Bitmap bitmap = MediaStore.Images.Media.getBitmap(this._context.getContentResolver(), resized); float multiplier = 1.0f; while (bitmap.getWidth() * multiplier < side && bitmap.getHeight() * multiplier < side) { multiplier += 1; } Matrix matrix = new Matrix(); matrix.postScale(multiplier, multiplier); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); builder = builder.setLargeIcon(bitmap); } try { Notification note = builder.build(); if (persistent) note.flags = note.flags | Notification.FLAG_NO_CLEAR; if (sticky) { note.flags = note.flags | Notification.FLAG_ONGOING_EVENT; JSONObject json = new JSONObject(); json.put("title", title); json.put("message", message); json.put("script", script); json.put("persistent", persistent); json.put("sticky", sticky); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putString(BaseScriptEngine.STICKY_NOTIFICATION_PARAMS, json.toString()); e.commit(); } NotificationManager noteManager = (NotificationManager) this._context.getSystemService(android.content.Context.NOTIFICATION_SERVICE); noteManager.notify(BaseScriptEngine.NOTIFICATION_ID, note); } catch (UnsupportedOperationException e) { // Added so that the mock test cases could still execute. } return true; } catch (Exception e) { LogManager.getInstance(this._context).logException(e); } return false; } @ScriptingEngineMethod(language = "All", assetPath = "all_cancel_script_note.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { }) public void cancelScriptNotification() { NotificationManager noteManager = (NotificationManager) this._context.getSystemService(android.content.Context.NOTIFICATION_SERVICE); noteManager.cancel(BaseScriptEngine.NOTIFICATION_ID); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.remove(BaseScriptEngine.STICKY_NOTIFICATION_PARAMS); e.commit(); } private Intent constructScriptIntent(String script) { Intent intent = new Intent(ManagerService.RUN_SCRIPT_INTENT); intent.putExtra(ManagerService.RUN_SCRIPT, script); return intent; } @ScriptingEngineMethod(language = "All", assetPath = "all_show_native_dialog.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "title", "message", "confirmLabel", "cancelLabel", "confirmScript", "cancelScript", "tag", "priority" }) public void showNativeDialog(final String title, final String message, final String confirmTitle, final String cancelTitle, final String confirmScript, final String cancelScript) { DialogActivity.showNativeDialog(this._context, title, message, confirmTitle, cancelTitle, confirmScript, cancelScript, null, 0); } @ScriptingEngineMethod(language = "All", assetPath = "all_show_native_dialog.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "title", "message", "confirmLabel", "cancelLabel", "confirmScript", "cancelScript", "tag", "priority" }) public void showNativeDialog(final String title, final String message, final String confirmLabel, final String cancelLabel, final String confirmScript, final String cancelScript, String tag, int priority) { DialogActivity.showNativeDialog(this._context, title, message, confirmLabel, cancelLabel, confirmScript, cancelScript, tag, priority); } @ScriptingEngineMethod(language = "All", assetPath = "all_clear_native_dialogs.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "tag" }) public void clearNativeDialogs() { DialogActivity.clearNativeDialogs(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_clear_native_dialogs.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "tag" }) public void clearNativeDialogs(String tag) { DialogActivity.clearNativeDialogs(this._context, tag, null); } @ScriptingEngineMethod(language = "All", assetPath = "all_show_app_launch_note.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "title", "message", "packageName" }) public boolean showApplicationLaunchNotification(String title, String message, String applicationName, long displayWhen) { return this.showApplicationLaunchNotification(title, message, applicationName, new HashMap<String, Object>(), null); } @ScriptingEngineMethod(language = "All") public boolean updateWidget(final String title, final String message, final String applicationName) { return this.updateWidget(title, message, applicationName, new HashMap<String, Object>(), null); } protected void updateWidget(Map<String, Object> parameters) { Intent intent = new Intent(ManagerService.UPDATE_WIDGETS); intent.setClass(this._context, ManagerService.class); for (Object keyObj : parameters.keySet()) { String key = keyObj.toString(); intent.putExtra(key, parameters.get(key).toString()); } this._context.startService(intent); if (parameters.containsKey("identifier")) { String identifier = parameters.get("identifier").toString(); JSONObject params = new JSONObject(); for (String key : parameters.keySet()) { try { params.put(key, parameters.get(key).toString()); } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } } SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); e.putString("WIDGET_UPDATE_" + identifier, params.toString()); e.commit(); } } protected Map<String, Object> fetchWidgetMap(String identifier) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); String key = "WIDGET_UPDATE_" + identifier; Map<String, Object> params = new HashMap<>(); if (prefs.contains(key)) { try { JSONObject json = new JSONObject(prefs.getString(key, "{}")); JSONArray names = json.names(); for (int i = 0; i < names.length(); i++) { String name = names.getString(i); params.put(name, json.get(name)); } } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } } return params; } protected List<String> widgetsList() { String prefix = "WIDGET_UPDATE_"; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); ArrayList<String> widgets = new ArrayList<>(); for (String key : prefs.getAll().keySet()) { if (key.startsWith(prefix)) widgets.add(key.substring(prefix.length())); } return widgets; } @ScriptingEngineMethod(language = "All", assetPath = "all_schedule_script.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "identifier", "dateString", "script" }) public void scheduleScript(String identifier, String dateString, String script) { ScheduleManager.updateScript(this._context, identifier, dateString, script); } @ScriptingEngineMethod(language = "All", assetPath = "all_cancel_scheduled_script.html", category = R.string.docs_script_category_dialogs_notifications, arguments = { "identifier" }) public void cancelScheduledScript(String identifier) { ScheduleManager.updateScript(this._context, identifier, null, null); } protected boolean broadcastIntent(final String action, final Map<String, Object> extras) { Intent intent = new Intent(action); if (extras != null) { for (Entry<String, Object> e : extras.entrySet()) { intent.putExtra(e.getKey(), e.getValue().toString()); } } this._context.sendBroadcast(intent); return true; } public static Object runScript(Context context, String script) { return BaseScriptEngine.runScript(context, script, null); } public static Object runScript(Context context, String script, Map<String, Object> objects) { context = context.getApplicationContext(); try { if (SchemeEngine.canRun(script)) { SchemeEngine engine = new SchemeEngine(context, objects); return engine.evaluateSource(script); } else if (JavaScriptEngine.canRun(script)) { JavaScriptEngine engine = new JavaScriptEngine(context); return engine.runScript(script, "extras", objects); } } catch (RuntimeException e) { LogManager.getInstance(context).logException(e); } return null; } protected boolean updateConfig(Map<String, Object> config) { return PurpleRobotApplication.updateFromMap(this._context, config); } @ScriptingEngineMethod(language = "All", assetPath = "all_update_config.html", category = R.string.docs_script_category_configuration, arguments = { "key", "value" }) public boolean updateConfig(String key, Object value) { Map<String, Object> values = new HashMap<>(); values.put(key, value); return PurpleRobotApplication.updateFromMap(this._context, values); } public Object valueFromString(String key, String string) { try { JSONObject json = new JSONObject(string); if (json.has(key)) { Object value = json.get(key); if (value instanceof JSONObject) value = this.jsonToMap((JSONObject) value); else if (value instanceof JSONArray) value = this.jsonToList((JSONArray) value); return value; } } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } return null; } private Map<String, Object> jsonToMap(JSONObject object) { Map<String, Object> map = new HashMap<>(); Iterator<String> keys = object.keys(); while (keys.hasNext()) { String key = keys.next(); try { Object value = object.get(key); if (value instanceof JSONObject) value = this.jsonToMap((JSONObject) value); else if (value instanceof JSONArray) value = this.jsonToList((JSONArray) value); map.put(key, value); } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } } return map; } private List<Object> jsonToList(JSONArray array) { List<Object> list = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { try { Object value = array.get(i); if (value instanceof JSONObject) value = this.jsonToMap((JSONObject) value); else if (value instanceof JSONArray) value = this.jsonToList((JSONArray) value); list.add(value); } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } } return list; } public List<String> fetchNamespaceList() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); ArrayList<String> list = new ArrayList<>(); list.add(""); try { JSONArray namespaces = new JSONArray(prefs.getString(BaseScriptEngine.SCRIPT_ENGINE_NAMESPACES, "[]")); for (int i = 0; i < namespaces.length(); i++) { list.add(namespaces.getString(i)); } } catch (JSONException e) { LogManager.getInstance(this._context).logException(e); } return list; } public Map<String, Object> fetchNamespaceMap(String namespace) { Map<String, Object> map = new HashMap<>(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Map<String, ?> all = prefs.getAll(); String prefix = namespace + " - " + BaseScriptEngine.SCRIPT_ENGINE_PERSISTENCE_PREFIX; if (namespace.length() == 0) prefix = BaseScriptEngine.SCRIPT_ENGINE_PERSISTENCE_PREFIX; for (String key : all.keySet()) { if (key.indexOf(prefix) == 0) map.put(key.substring(prefix.length()), all.get(key)); } return map; } public List<String> fetchTriggerIdList() { return TriggerManager.getInstance(this._context).triggerIds(); } public List<String> fetchSnapshotIdList() { ArrayList<String> times = new ArrayList<>(); for (long time : SnapshotManager.getInstance(this._context).snapshotTimes()) times.add("" + time); return times; } @ScriptingEngineMethod(language = "All", assetPath = "all_take_snapshot.html", category = R.string.docs_script_category_data_collection, arguments = {"source" }) public String takeSnapshot(String source) { try { return "" + SnapshotManager.getInstance(this._context).takeSnapshot(this._context, source, null); } catch (EmptySnapshotException e) { } return null; } @ScriptingEngineMethod(language = "All", assetPath = "all_delete_snapshot.html", category = R.string.docs_script_category_data_collection, arguments = { "snapshotId" }) public void deleteSnapshot(String snapshotId) { SnapshotManager.getInstance(this._context).deleteSnapshot(Long.parseLong(snapshotId)); } public Map<String, Object> fetchSnapshotMap(String timestamp) { JSONObject json = SnapshotManager.getInstance(this._context).jsonForTime(Long.parseLong(timestamp), true); return this.jsonToMap(json); } public Map<String, Object> fetchTriggerMap(String id) { return TriggerManager.getInstance(this._context).fetchTrigger(this._context, id); } @ScriptingEngineMethod(language = "All", assetPath = "all_delete_trigger.html", category = R.string.docs_script_category_triggers_automation, arguments = { "triggerId" }) public boolean deleteTrigger(String id) { return TriggerManager.getInstance(this._context).deleteTrigger(id); } @ScriptingEngineMethod(language = "All", assetPath = "all_clear_triggers.html", category = R.string.docs_script_category_triggers_automation, arguments = { }) public void clearTriggers() { LogManager.getInstance(this._context).log("script_clear_triggers", null); for (String id : this.fetchTriggerIdList()) { this.deleteTrigger(id); } } @SuppressWarnings({ "unchecked", "rawtypes" }) public void fetchLabelsInterface(String appContext, String instructions, Map<String, Object> labels) { Intent labelIntent = new Intent(); labelIntent.setClass(this._context, LabelActivity.class); labelIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); labelIntent.putExtra(LabelActivity.LABEL_CONTEXT, appContext); if (instructions != null) labelIntent.putExtra(LabelActivity.INSTRUCTIONS, instructions); labelIntent.putExtra(LabelActivity.TIMESTAMP, ((double) System.currentTimeMillis())); Bundle labelsBundle = new Bundle(); for (String key : labels.keySet()) { Map<String, Object> labelMap = (Map<String, Object>) labels.get(key); Bundle labelBundle = new Bundle(); for (String labelKey : labelMap.keySet()) { Object o = labelMap.get(labelKey); if (o instanceof String) labelBundle.putString(labelKey, o.toString()); else if (o instanceof Double) labelBundle.putDouble(labelKey, (Double) o); else if (o instanceof ArrayList) { ArrayList<String> listItems = new ArrayList<>(); for (Object item : ((ArrayList) o)) { listItems.add(item.toString()); } labelBundle.putStringArrayList(labelKey, listItems); } else Log.e("PR", "UNKNOWN OBJECT: " + o.getClass().getCanonicalName() + " -- " + labelKey); } labelsBundle.putParcelable(key, labelBundle); } labelIntent.putExtra(LabelActivity.LABEL_DEFINITIONS, labelsBundle); this._context.startActivity(labelIntent); } // TODO: Document API call public void addModel(String jsonUrl) { ModelManager.getInstance(this._context).addModel(jsonUrl); } // TODO: Document API call public void deleteModel(String jsonUrl) { ModelManager.getInstance(this._context).deleteModel(jsonUrl); } // TODO: Document API call public void enableModel(String jsonUrl) { ModelManager.getInstance(this._context).enableModel(jsonUrl); } // TODO: Document API call public void disableModel(String jsonUrl) { ModelManager.getInstance(this._context).disableModel(jsonUrl); } @ScriptingEngineMethod(language = "All", assetPath = "all_set_upload_url.html", category = R.string.docs_script_category_configuration, arguments = { "url" }) public void setUploadUrl(String uploadUrl) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); Editor e = prefs.edit(); if (uploadUrl != null) { if (Uri.parse(uploadUrl) != null) e.putString(DataUploadPlugin.UPLOAD_URI, uploadUrl); } else e.remove(DataUploadPlugin.UPLOAD_URI); e.commit(); } @ScriptingEngineMethod(language = "All", assetPath = "all_get_upload_url.html", category = R.string.docs_script_category_configuration, arguments = { }) public String getUploadUrl() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context); return prefs.getString(DataUploadPlugin.UPLOAD_URI, null); } @ScriptingEngineMethod(language = "All", assetPath = "all_scan_nfc.html", category = R.string.docs_script_category_data_collection, arguments = { }) public boolean scanNFC() { return NfcActivity.startScan(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_can_scan_nfc.html", category = R.string.docs_script_category_data_collection, arguments = { }) public boolean canScanNFC() { return NfcActivity.canScan(this._context); } @ScriptingEngineMethod(language = "All", assetPath = "all_cancel_nfc_scan.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void cancelNFCScan() { NfcActivity.cancelScan(); } public List<String> fetchToneList() { ArrayList<String> tones = new ArrayList<>(); RingtoneManager rm = new RingtoneManager(this._context); rm.setType(RingtoneManager.TYPE_NOTIFICATION); Cursor cursor = rm.getCursor(); do { String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); tones.add(title); } while (cursor.moveToNext()); cursor.deactivate(); String[] included = this._context.getResources().getStringArray(R.array.sound_effect_labels); for (String tone : included) tones.add(tone); Collections.sort(tones); return tones; } @ScriptingEngineMethod(language = "All", assetPath = "all_transmit_probe_buffer.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void transmitProbeBuffer() { LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(this._context); Intent intent = new Intent(edu.northwestern.cbits.purple_robot_manager.probes.Probe.PROBE_TRANSMIT_BUFFER); localManager.sendBroadcast(intent); } @ScriptingEngineMethod(language = "All", assetPath = "all_transmit_now.html", category = R.string.docs_script_category_data_collection, arguments = { }) public void transmitNow() { LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(this._context); Intent intent = new Intent(OutputPlugin.FORCE_UPLOAD); localManager.sendBroadcast(intent); } }